第 8 课:模型微调 Llama Factory
两种模型微调的方式:Llama factory 和 verl,这里先介绍 Llama factory
(一)模型微调
1. 什么是模型微调
模型微调(Finetuning)是指:
在一个已经训练好的大模型(通常是大规模预训练语言模型,如 GPT、LLaMA、BERT)的基础上,再用一个特定领域的小数据集对其进行二次训练,从而让模型在保留原有通用能力的同时,适应特定任务或领域的需求。
你可以把预训练模型看成一个已经读完中学、大学的人,拥有很强的通识能力; 而微调就是让他在这个基础上接受某个专业的“职前培训”,
| 模型阶段 | 类比 | 举例 |
|---|---|---|
| 预训练 | 读完通识课程 | GPT-3 预训练看了千亿token文本 |
| 微调 | 定向实习/专业培训 | 用医疗问答数据训练得到医疗 GPT 模型 |
| 指令微调 | 接受任务型训练 | 用 "问→答" 形式训练让模型听懂指令 |
| RLHF | 上岗+反馈优化 | 模型输出由人类偏好打分后再强化学习 |
预训练
-
是指用海量通用语料(如网络文本、百科、小说、代码等)训练语言模型。这个阶段让模型学习语言结构、常识、推理能力等通用知识。
-
举例:比如 GPT-3、LLaMA-2 都在这个阶段接触了数千亿 token 的文本,例如:
“莎士比亚是谁?”、“Python 怎么写 for 循环?”、“华盛顿在哪一年就职?”
-
此时的模型非常聪明,但不专精。就像大学毕业生一样,知识广,但没有专业经验。
微调(Fine-tuning)
-
微调是在预训练模型的基础上,用某一类数据进一步训练,让模型掌握特定任务或特定领域知识。
-
举例:你用几千条“医疗问答”训练模型,让它变成懂医疗的 GPT。
问:“血糖升高会引起什么后果?” → 模型回答得像医生。
- 模型这时就像上过“医学实习”的大学生,虽然不是博士,但能给出合理答案。
指令微调(Instruction Tuning)
-
是微调的一种,训练模型去理解“用户在给它发任务指令”,比如:
-
“请总结下面这段话。”
-
“将下面文字翻译成英文。”
-
“写一首诗。”
-
-
举例:你训练模型理解:
{
"instruction": "总结以下内容",
"input": "人工智能是...",
"output": "人工智能是一种模拟人类智能的技术。"
}
模型变得“能听懂任务了”,能“看指令做事”,这就是你熟悉的 ChatGPT 风格的 LLM。
RLHF(Reinforcement Learning with Human Feedback)
- RLHF 是指:用人类偏好对模型输出打分(哪个回答更好、更自然、更安全),再用强化学习优化模型,让它输出更符合人类偏好的回答。
人类打分 → 训练出奖励模型 → 模型按“人类偏好”优化。
-
给模型两个回答:
-
回答 A:内容对,但语气生硬
-
回答 B:内容对,语气自然
-
-
我们打分说 B 更好。模型会被训练去更倾向生成 B 的风格。
2. 什么情况下需要微调
| 应用场景 | 是否需要微调? | 说明 |
|---|---|---|
| 你想让模型掌握行业知识(如法律、医疗) | ✅ 推荐微调 | 通用模型知识不足 |
| 你要做一个特定功能的模型(如总结、翻译) | ✅ 推荐微调 | 通用模型可能风格不一致 |
| 你有自己的语料库(如公司客服数据) | ✅ 推荐微调 | 提高准确性和上下文理解 |
| 只想问通用问题,比如写作文/写代码 | ❌ 不需要微调 | 通用模型就足够 |
| 想用指令提示(prompt)就解决 | ⚠️ 可用 prompt tuning | 轻量解决方案 |
3. 微调的原理
基础原理:
预训练语言模型的目标是最小化语言建模损失:
而微调的目标是:最小化特定任务的数据损失,比如:
- 问答:让模型在给定问题下给出正确回答;
- 翻译:给定英文,让模型生成正确中文;
- 总结:给定一段文章,模型输出总结。
这实际上就是“继续训练”,只不过是:
- 使用小规模新数据;
- 调整某部分模型参数(全量 or LoRA);
- 学习方向是 “模型参数微调以适应任务”。
4. 微调方式分类
| 微调类型 | 参数量 | 显存消耗 | 是否修改原始模型参数 | 适用场景 |
|---|---|---|---|---|
| 全量微调 | 很多(全部) | 高 | 是 | 高精度任务,小模型 |
| LoRA 微调 | 少 | 低 | 否(添加低秩矩阵) | 大模型任务,低成本部署 |
| Prefix Tuning | 极少 | 很低 | 否 | 多任务共用主模型 |
| QLoRA | 非常少 | 极低 | 否,支持 4-bit 权重 | 消耗极小的设备上训练 |
举例:你要训练一个“法律助手”
- 通用 LLM 对于中文法律条文的理解可能模糊
- 你准备了几千条法律问答(Q&A)
- 使用 LLaMA Factory + LoRA 微调
- 输出效果将更正式、精准、有条文引用
注意:之前说的 “指令微调(Instruction Tuning)” 的功能是定义训练数据的格式
典型格式为:
{ "instruction": "翻译成英文", "input": "今天天气很好。", "output": "The weather is nice today." }这种格式可以用于:全量微调, LoRA 微调, Prefix Tuning, QLoRA 等等
也就是说:指令微调”是“要做的任务”,不是“怎么做的技术”✨
Lora 的数学原理
大型模型参数量巨大(几十亿),全量微调成本太高。每一层的参数都以矩阵形式计算和保存。
而我们观察到:在微调过程中,大多数参数的变化是低秩(low-rank)矩阵的扰动。
于是:我们不直接微调原始参数矩阵,而是:
让参数改变量用一个低秩矩阵近似表示,只训练这个小矩阵。
例如,假设你要微调的模型中有某个全连接层参数矩阵:
LoRA 假设我们不直接更新 ,而是引入两个小矩阵 ,只训练它们:
其中 ,即:
- 原始参数 :不变(冻结)
- 改变量 :可训练
输入为 ,原本输出:
现在变为:
这就是 LoRA 的核心逻辑:“用一个小矩阵对原有模型输出进行可学习的扰动”
而训练的参数量的变化如下:
- 原始层参数量:
- LoRA 参数量:
例如:取 d =4096, k = 4096, r =8,
则全量参数为 4096*4096 =16,777,216 , Lora 参数为 8*(4096+4096)=65,536,仅占 0.4%!
QLoRA的数学原理
QLoRA 在Lora 的基础上,把模型主权重矩阵 W 不止做了冻结,还做了量化(Quantization),比如把 float16/full 变成了 4bit
在训练参数上,仍然是只训练插入的低秩矩阵
原因:
- 语言模型的知识集中在主权重中,LoRA 插件负责微调输出即可;
- 4-bit 权重足以 表达主模型知识(推理保留);
- LoRA 插件全保留浮点精度,保证梯度传播质量。
| 方法 | 显存(LLaMA-7B, batch=1) |
|---|---|
| 全量微调 | ~25 GB |
| LoRA | ~11 GB |
| QLoRA | ~5.5 GB |
Prefix tuning 的原理
Prefix Tuning 是一种参数高效微调方法,它不修改原始模型参数,也不训练权重矩阵,而是训练一小段“可学习的向量”,作为每一层注意力机制的“前缀”输入。
本质:不动模型,只在前面加点引导提示(prefix)。
这是因为,大语言模型(如 Transformer)由多层自注意力模块组成,每一层的输入都会生成 Query、Key、Value 向量,然后做注意力计算:
Prefix Tuning 的核心思路是:
- 在每一层 attention 的输入中插入一些额外的“可学习向量”
- 这些向量不是从输入文本计算来的,而是训练出来的参数(prefix embedding)
- 最终影响 attention 输出,进而改变整个模型行为
数学原理
假设:
-
原始输入序列是:
-
每层 attention 的输入为 query/key/value 向量:
我们引入一个固定长度的 prefix token embedding 向量组(例如长度为 (p)):
它们是训练得到的、与输入无关的向量。
然后我们在 attention 时,将 Key、Value 拼接为:
而 Query 还是原样不变。
最终 attention 变成:
📌 注意:
- 模型主参数 () 都不变;
- 只训练 prefix 向量 ();
- 不影响模型结构,不改变 inference 流程(只是前面“加点料”);
5. 优势总结
| 优势 | 说明 |
|---|---|
| 减少训练资源 | 只训练少量参数或 adapter |
| 保留预训练模型的能力 | 不会忘掉原来学到的通用知识 |
| 提高特定任务性能 | 快速适应新领域数据分布 |
| 可控性强 | 你可以精准控制输出行为 |
微调 vs Prompt Engineering:全面对比
比较维度 Prompt Engineering(提示工程) Fine-tuning(模型微调) 定义 利用精心设计的提示词(prompt)引导已有模型回答 在已有模型基础上继续训练,让其学会新任务 工具依赖 无需改动模型,只改输入 需要代码/训练框架(如 LLaMA Factory) 数据需求 1~100 条也能生效 通常需要 ≥ 数百条有标注的数据 资源消耗 几乎为 0,推理时花时间 显卡/CPU 时间、显存、存储资源需求大 调整难度 上手简单,适合非技术用户 需具备基本的 ML/代码能力 泛化能力 利用原模型知识,很强 若微调数据小且任务特殊,泛化能力可能下降 记忆能力 无法“记住”新知识,重启后提示需重写 微调后模型“记住”新能力,无需提示词 控制输出风格 限制较多,靠 prompt 迂回控制 可精确控制模型输出风格、术语等 多轮对话一致性 复杂对话容易崩塌 微调能强化长对话结构或角色设定 部署一致性 无需部署新模型 部署前需保存新模型(或 Adapter) 参数更新 不修改模型参数 会更新模型或部分参数(如 LoRA) 提升效果 效果中等,有时 prompt 长反而出错 效果明显,尤其在特定任务/领域表现优异
(二)Llama Factory
LLaMA Factory 是一个开源项目,旨在简化对 Hugging Face 上的 LLaMA 系列模型(包括 LLaMA、Baichuan、ChatGLM、Qwen、Mistral、DeepSeek 等)的微调(Fine-tuning)过程。
它支持以下多种微调策略:
- Full fine-tuning
- LoRA / QLoRA
- Prefix Tuning / P-Tuning
- Adapters
同时支持的数据格式:
ShareGPT,Alpaca,OASST1,HH-RLHF,UltraChat,Firefly,Belle, 自定义 JSON 等。
步骤一:安装 LLaMA Factory
git clone https://github.com/hiyouga/LLaMA-Factory.git
cd LLaMA-Factory
pip install -r requirements.txt
如果你只需要基本的功能,可以精简依赖:
pip install transformers datasets peft accelerate
步骤二:数据准备
LLaMA Factory 支持多种数据格式,最推荐使用标准的 JSON 格式,示例如下:
[
{
"instruction": "给我写一首诗",
"input": "关于春天的",
"output": "春风又绿江南岸,明月何时照我还。"
}
]
数据格式说明:
| 字段 | 含义 |
|---|---|
| instruction | 任务指令,如“翻译以下句子” |
| input | 可选输入(有些任务不需要) |
| output | 期望模型输出 |
步骤三:准备模型
在 llama-factory 的 Hugging Face Hub 下载你要微调的模型,比如:
huggingface-cli login
model_name_or_path = "meta-llama/Llama-2-7b-hf"
你也可以使用 Deepseek、ChatGLM、Baichuan、Qwen 等支持的模型。
步骤四:启动微调脚本
使用 CLI 启动微调任务:
python src/train_bash.py \
--stage sft \
--do_train \
--model_name_or_path path_or_name \
--dataset_dir data/ \
--dataset your_dataset_name.json \
--template default \
--finetuning_type lora \
--output_dir saves/your_model \
--per_device_train_batch_size 2 \
--gradient_accumulation_steps 8 \
--num_train_epochs 3 \
--learning_rate 5e-5 \
--fp16
🔧 你可以将上面命令写入 shell 脚本方便管理
常见参数解释:
| 参数 | 说明 |
|---|---|
--stage sft | 微调阶段:sft(监督微调) |
--finetuning_type lora | LoRA 微调方式(支持 full、lora、qlora 等) |
--template | prompt 模板,支持 default、chatglm、baichuan 等 |
--per_device_train_batch_size | 单卡批量大小 |
--gradient_accumulation_steps | 梯度累计步数 |
--fp16 | 是否使用半精度训练(节省显存) |
步骤五:模型使用
完成训练后,微调模型保存在 --output_dir 指定目录下。
加载方式如下:
from transformers import AutoModelForCausalLM, AutoTokenizer
from peft import PeftModel
base_model = AutoModelForCausalLM.from_pretrained("meta-llama/Llama-2-7b-hf")
tokenizer = AutoTokenizer.from_pretrained("meta-llama/Llama-2-7b-hf")
model = PeftModel.from_pretrained(base_model, "saves/your_model")
你可以使用提供的推理脚本 src/web_demo.py 来进行测试:
python src/web_demo.py \
--model_name_or_path meta-llama/Llama-2-7b-hf \
--adapter_path saves/your_model
这样会启动一个 Streamlit 的网页界面,可用于测试你的微调模型。
| 步骤 | 内容 |
|---|---|
| 1 | 安装依赖 |
| 2 | 准备模型(LLaMA/Qwen等) |
| 3 | 准备数据集(Alpaca 格式等) |
| 4 | 配置微调命令(LoRA 推荐) |
| 5 | 启动训练 |
| 6 | 使用推理脚本测试结果 |